<?php

namespace app\api\controller;

use app\BaseController;
use app\common\service\ByteService;
use app\common\service\WechatOfficialService;
use app\common\service\WechatService;
use think\facade\Db;
use think\facade\Log;
use think\response\Json;

class PayNotify extends BaseController
{
    /**小程序回调
     * @return void
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function miniApp(): void
    {
        Log::channel('pay_notify')->record(['wechat' => file_get_contents("php://input")]);

        $service = new WechatService();

        $this->wechat($service);
    }

    /**公众号回调
     * @return void
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function official(): void
    {
        Log::channel('pay_notify')->record(['official' => file_get_contents("php://input")]);
        $service = new WechatService((new WechatOfficialService())->getConfig('appid'));

        $this->wechat($service);
    }

    /**微信支付回调通知
     * @param \app\common\service\WechatService $wechat
     * @return void
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function wechat(WechatService $wechat): void
    {
        $response = $wechat->payApp()->handlePaidNotify(function ($message, $fail) {
            if ($message['return_code'] !== 'SUCCESS' || $message['result_code'] !== 'SUCCESS') {
                return $fail('通信失败，请稍后再通知我');
            }

            Db::startTrans();
            try {
                update_pay_status($message['out_trade_no'], $message['transaction_id']);
                Db::commit();
            } catch (\Throwable $throwable) {
                Db::rollback();
                Log::channel('pay_notify')->record(['wechat_err' => $throwable->getMessage()]);
                return $fail('通信失败，请稍后再通知我');
            }

            return true;
        });

        $response->send();
    }

    /**抖音支付回调
     * @param \app\common\service\ByteService $byte
     * @return \think\response\Json
     */
    public function byte(ByteService $byte): Json
    {
        Log::channel('pay_notify')->record(['byte' => file_get_contents("php://input")]);

        $this->validate($this->request->param(), [
            'timestamp'     => 'require|integer',
            'nonce'         => 'require|max:4',
            'msg'           => 'require',
            'type'          => 'require',
            'msg_signature' => 'require',
        ]);

        if (!$byte->check_sign($this->request->param())) {
            abort(400, '验签失败');
        }

        $msg = json_decode(htmlspecialchars_decode(htmlspecialchars_decode(request()->param('msg'))), true);

        Db::startTrans();
        try {
            update_pay_status($msg['cp_orderno'], $msg['channel_no']);
            Db::commit();
        } catch (\Throwable $throwable) {
            Db::rollback();
            Log::channel('pay_notify')->record(['byte_error' => $throwable->getMessage()]);
            abort(400, $throwable->getMessage());
        }

        return json([
            "err_no"   => 0,
            "err_tips" => "success"
        ]);
    }
}